﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using WindowsAPI.Windows;

namespace WindowsAPI
{
    public static partial class Keyboard
    {
        /// <summary>Структура описания события клавиатуры</summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct KbDllHookStruct
        {
            /// <summary>Код виртуальной клавиши</summary>
            public readonly VirtualKey VirtualKeyCode;
            /// <summary>Скан-код клавиши</summary>
            public readonly uint ScanCode;
            /// <summary>Флаги дополнительных клавиш</summary>
            public readonly KeyFlags Flags;
            /// <summary>Отметка времени</summary>
            public readonly uint Time;
            /// <summary>Указатель на дополнительную информацию</summary>
            public IntPtr ExtraInfo;

            public override string ToString()
            {
                return string.Format("Key:{0}({1}),F:{2},T{3}", VirtualKeyCode, ScanCode, Flags, TimeSpan.FromMilliseconds(Time));
            }
        }


        /// <summary>Список клавиш</summary>
        [Serializable]
        public sealed class KeyList : List<VirtualKey>, IEquatable<KeyList>
        {
            /// <summary>Список клавиш</summary>
            public KeyList() { }

            public KeyList(int Capasity) : base(Capasity) { }
            public KeyList(IEnumerable<VirtualKey> Collection) : base(Collection) { }

            public KeyList(string KeyString)
            {
                var lv_KeysStr = KeyString.Split('+');
                var lv_Keys = Array.ConvertAll(lv_KeysStr,
                                               str => (VirtualKey)Enum.Parse(typeof(VirtualKey), str));
                AddRange(lv_Keys);
            }

            public void CheckKey(WM Message, VirtualKey VirtualKeyCode)
            {
                if(Message == WM.KEYDOWN && !Exists(K => K == VirtualKeyCode))
                {
                    Add(VirtualKeyCode);
                    //Sort();
                }
                else if(Message == WM.KEYUP)
                    RemoveAll(K => K == VirtualKeyCode);
            }

            public override int GetHashCode()
            {
                var lv_HashCode = 0x19919;
                for(var i = 0; i < Count; i++)
                    lv_HashCode ^= this[i].GetHashCode();
                return lv_HashCode;
            }

            public override bool Equals(object obj) { return Equals(obj as KeyList); }

            public bool Equals(KeyList other)
            {
                if(ReferenceEquals(other, null)) return false;

                if(other.Count != Count) return false;
                for(var i = 0; i < Count; i++)
                    if(this[i] != other[i])
                        return false;
                return true;
            }


            public override string ToString()
            {
                if(Count == 0) return "";
                var lv_Result = this[0].ToString();
                for(var i = 1; i < Count; i++)
                    lv_Result += string.Format("+{0}", this[i]);
                return lv_Result;
            }

            public static bool operator ==(KeyList A, KeyList B)
            {
                return ReferenceEquals(A, null) && ReferenceEquals(B, null)
                    || !ReferenceEquals(A, null) && A.Equals(B);
            }

            public static bool operator !=(KeyList A, KeyList B) { return !(A == B); }

            public static explicit operator KeyList(string ShortCut) { return new KeyList(ShortCut); }

            public static implicit operator string(KeyList List) { return List.ToString(); }
        }

        /// <summary>Флаги дополнительных клавиш</summary>
        [Serializable, Flags]
        public enum KeyFlags : uint
        {
            /// <summary>Клавиша на основной клавиатуре</summary>
            MovingDown = 0x00000000,
            /// <summary>Клавиша на дополнительной клавиатуре</summary>
            AdditionalKey = 0x00000001,
            /// <summary>Зарезервиро 1</summary>
            Reserved1 = 0x00000002,
            /// <summary>Зарезервировано 2</summary>
            Reserved2 = 0x00000004,
            /// <summary>Зарезервиро 3</summary>
            Reserved3 = 0x00000008,
            /// <summary>Вставлялось событие</summary>
            InsertEvent = 0x00000010,
            /// <summary>Клавиша Alt активирована</summary>
            AltSet = 0x00000020,
            /// <summary>Зарезервировано 4</summary>
            Reserved4 = 0x00000040,
            /// <summary>Клавиша отпускается</summary>
            MovingUp = 0x00000080
        }
    }
}
